
/**
 * 用于将已上传eolink的后端接口文档，转换为精确的ts类型
 */
import type { ParamItem, UnionParamItem, ApiDataType } from './types';

import readConfig from "../../common/config-read.js";
import { requestTypeMap, paramTypeMap } from "./const.js"

type EolinkGetApiParams = {
  spaceKey: string,
  projectHashKey: string,
  apiID: number
}

const matchParamsByUrl = (): EolinkGetApiParams[] => {
  const urlParamsList: EolinkGetApiParams[] = [];
  process.argv.forEach(item => {
    const projectHashKey = item.match(/\/inside\/(.*?)\//)?.[1];
    const spaceKey = item.match(/\?spaceKey\=(.*)/)?.[1];
    const apiID = item.match(/\/detail\/(.*?)\?/)?.[1];
    if (apiID && projectHashKey && spaceKey) {
      urlParamsList.push({ projectHashKey, spaceKey, apiID: Number(apiID) })
    }
  })
  console.log('process.argv', urlParamsList);
  return urlParamsList;
}


const createFormDataParams = (params: Record<string, any>) => {
  var formData = new FormData();
  Object.keys(params).forEach(element => {
    formData.append(element, params[element])
  });
  return formData;
}

const InterfaceType: Record<string, true> = {
  '12': true, // 数组
  '13': true, // 对象
}


function paramsListRecursion(list: UnionParamItem[], dataStructureList: ApiDataType['apiInfo']['dataStructureList']): ParamItem[] {
  let arr: ParamItem[] = [];
  list.forEach(item => {
    if (item.structureID) {
      return arr.push(...(dataStructureList?.[item.structureID]?.structureData || []))
    }
    if (item.childList && item.childList.length) {
      item.childList = paramsListRecursion(item.childList, dataStructureList);
    }
    arr.push(item)
  })
  return arr;
}

const defaultNameFun = (str: string, baseInfo: ApiDataType['apiInfo']['baseInfo']) => {
  if (!str) return '';
  let pathArr = str.split(/\//).slice(-3)?.filter(path => path);
  pathArr = pathArr
    .map((path) => path
      .replace(/-\w/, (v) => v.replace('-', '').toUpperCase())
      .replace(/\W/, '')
      .replace(/^\w/, (v) => v.toUpperCase())
    );
  return requestTypeMap[baseInfo.apiRequestType].toLocaleLowerCase() + pathArr.join('');
}

/**
 * 用于递归查找出属性数不为1的子接口，并返回接口名称
 * @param list 接口属性列表
 * @param keyName 父级属性名
 * @returns 
 */
function getDeepenComplierRecursion(list: UnionParamItem[], keyName: string): [UnionParamItem[], string] {
  if (list.length === 1 && list[0].childList?.length) {
    return getDeepenComplierRecursion(list[0].childList, list[0].paramKey);
  }
  return [list, keyName];
}


/**
 * 处理选择解析指定参数，出现外层接口只有一个属性的情况，如
 * 
 * interface Record {
 *  a: string;
 *  b: string;
 * }
 * 
 * interface Data {
 *  record: Record[],
 * }
 * 
 * interface postListing {
 *  data: Data;
 * }
 * 这种情况下，递归返回子接口的类型有多个属性的子接口,
 * 并同时返回新接口名：此时使用defaultNameFun + 满足条件的子类型的上级属性名决定，以上为例接口为：
 * interface postListingRecord {
 *  a: string;
 *  b: string;
 * }
 * @param list 当前过滤后接口属性列表
 * @param baseInfo 接口信息，用于生成接口名
 * @param suffix 默认接口后缀，当list不为只有一个属性接口时，后续由该参数指定
 * @returns [子接口属性列表，接口名称]
 */
function getParamsInterfaceName(
  list: UnionParamItem[],
  baseInfo: ApiDataType['apiInfo']['baseInfo'],
  suffix: string): [ParamItem[], string] {
  let name = defaultNameFun(baseInfo.apiURI, baseInfo);
  if (list.length === 1 && list[0].childList?.length) {
    let [complierParams, keyName] = getDeepenComplierRecursion(list, list[0].paramKey);
    const UpperKeyName = keyName.replace(/^\w/, (v) => v.toUpperCase());
    return [complierParams, defaultNameFun(baseInfo.apiURI, baseInfo) + UpperKeyName];
  }
  return [list, name + suffix];
}
const Line = ({ attr, interfaceKey, required }: { attr: UnionParamItem; interfaceKey?: string; required: boolean; }) => {
  const propName = `${attr.paramKey}${required && attr.paramNotNull === '1' ? '?' : ''}`;
  const type = `${interfaceKey ? interfaceKey : paramTypeMap[attr.paramType]}`
  const paramName = `${attr.paramName ? `   // ${attr.paramName}` : ''}`;
  return `${propName}:  ${type}; ${paramName}`
}

const PanelContent = (attrs: ParamItem[], interfaceName: string, required: boolean): string => {
  return `${attrs
    .filter(({ paramType, childList }) => InterfaceType[paramType] && childList?.length)
    .map(attr => {
      const subInterfaceName = attr.paramKey.replace(/^\w/, (v) => v.toUpperCase());
      return PanelContent(attr.childList, subInterfaceName, required)
    }).join("")
    }
      
${interfaceName ? `interface ${interfaceName}` : ''} {${attrs.map(attr => {
      if (InterfaceType[attr.paramType] && attr.childList?.length) {

        const subInterfaceName = attr.paramKey.replace(/^\w/, (v) => v.toUpperCase());
        return `
      ${Line({ attr, required, interfaceKey: `${subInterfaceName}${attr.paramType === '12' ? '[]' : ''}` })}`;
      }
      return `
      ${Line({ attr, required })}`;
    }).join("")
    }
}`

}




export default function EolinkApiToTsType() {

  return new Promise<string>(async (resolve, reject) => {

    const eolinkConfig = readConfig('sources.eolink');
    if (!eolinkConfig?.Authorization && !(eolinkConfig.account && eolinkConfig.password)) {
      return reject('请填写eolink的Authorization或账号密码');
    }
    let Authorization = eolinkConfig?.Authorization;

    if (eolinkConfig.account && eolinkConfig.password) {
      // 
      await fetch('https://apis.eolink.com/userCenter/common/sso/login', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          "username": eolinkConfig.account,
          "type": 1,
          "password": eolinkConfig.password,
          "checkCodeType": 0,
          "client": 0,
          "appType": 0
        })


      }).then((response) => {
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        return response.json();
      })
        .then((response) => {

          if (response.success) {
            Authorization = response?.data?.jwt;
          }

        })
        .catch((err) => {
          reject(err)
        })
    }

    try {
      const formDatas = matchParamsByUrl();
      if (!formDatas.length) return reject('请输入要解析的eolink api接口地址')

      Promise.all<ApiDataType & EolinkGetApiParams>(formDatas.map((formData) => {
        return fetch('https://apis.eolink.com/api/apiManagementPro/Api/getApi', {
          method: 'POST',
          headers: {
            Authorization,
          },
          body: createFormDataParams(formData)
        }).then((response) => {
          return (response.json() as Promise<ApiDataType>).then(res => ({ ...res, ...formData }));
        })
      })).then((responses) => {

        resolve(responses.reduce((sum, response) => {
          if (response.statusCode !== '000000') {
            return sum + `\n\n\n // apiId为${response.apiID}的接口请求出错：` + (response.errorMsg || '可能参数出错了') + '\n\n\n';
          }

          const { apiInfo: { baseInfo, requestInfo, dataStructureList, restfulParam, urlParam, resultInfo } } = response;
          const resultInfoTree = paramsListRecursion(resultInfo[0]?.paramList, dataStructureList);

          return sum += PanelContent(...getParamsInterfaceName(resultInfoTree, baseInfo, 'Result'), true) + '\n\n' + PanelContent(...getParamsInterfaceName(paramsListRecursion(requestInfo, dataStructureList), baseInfo, 'Body'), true)

          // fs.appendFile('model.ts', PanelContent(...getParamsInterfaceName(resultInfoTree, baseInfo, 'Result'), true), (err) => {
          //   if (err) throw err;
          //   console.log('The "data to append" was appended to file!');
          // });

          // fs.appendFile('model.ts', PanelContent(...getParamsInterfaceName(paramsListRecursion(requestInfo, dataStructureList), baseInfo, 'Body'), true), (err) => {
          //   if (err) throw err;
          //   console.log('The file has been saved!');
          // });


          // console.log(baseInfo, requestInfo, dataStructureList, restfulParam, urlParam, resultInfo)
        }, ""))



      })
        .catch((err) => {
          reject(err)
        });
    } catch (err) {
      reject(err)
    }

  })


}




